package org.metasketch.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.metasketch.editor.toolbox.advanced.DeleteRelatedManager;
import org.metasketch.reflection.RefUtil;
import org.metasketch.reflection.ReflectionAnalyser;

import com.thoughtworks.xstream.annotations.XStreamOmitField;

public abstract class BaseModel extends CommonIdentified {

	@XStreamOmitField
	static RefUtil util = new RefUtil();

	@XStreamOmitField
	protected IdDatabase index = new IdDatabase();

	@XStreamOmitField
	protected ModelChangeManager modelChangeManager = new ModelChangeManager();

	public List<CommonIdentified> removeAllReferencesFromNodes(
			CommonIdentified node) {

		List<Object> processedNodes = new ArrayList<Object>();

		List<CommonIdentified> nodesToDelete = new ArrayList<CommonIdentified>();

		try {
			List<String> collections = ReflectionAnalyser
					.getNonNativeCollections(this.getClass());

			for (String fieldName : collections) {
				Collection collection = (Collection) util.getValue(this,
						fieldName);

				for (Object object : collection) {
					removeReferences(object, node, processedNodes,
							nodesToDelete);
				}

			}

			// return false;

			// for (CommonIdentified toDelete : nodesToDelete) {
			// removeAllReferencesFromNodes(toDelete);
			// }
			return nodesToDelete;

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// RefUtil util = new RefUtil();
		// util.
		return null;
	}

	private void removeReferences(Object object, CommonIdentified node,
			List<Object> processedNodes, List<CommonIdentified> nodesToDelete) {
		if (processedNodes.contains(object))
			return;

		processedNodes.add(object);

		try {
			List<String> objectFields = ReflectionAnalyser
					.getObjectFieldNames(object.getClass());
			for (String string : objectFields) {
				Object value = util.getValue(object, string);

				if (value == null)
					continue;

				if (value.equals(node)) {
					util.setNullValue(object, string);

					// TODO not sure this will work properly
					if (DeleteRelatedManager.isHit(node.getClass(),
							object.getClass(), string)
							&& object instanceof CommonIdentified)
						nodesToDelete.add((CommonIdentified) object);
				}

				removeReferences(value, node, processedNodes, nodesToDelete);
			}

			List<String> collectionFields = ReflectionAnalyser
					.getNonNativeCollections(object.getClass());
			for (String string : collectionFields) {
				Collection collection = (Collection) util.getValue(object,
						string);
				if (collection.contains(node)) {
					collection.remove(node);

					// TODO not sure this will work properly
					if (DeleteRelatedManager.isHit(node.getClass(),
							object.getClass(), string)
							&& object instanceof CommonIdentified)
						nodesToDelete.add((CommonIdentified) object);

				}

				for (Object object2 : collection) {
					removeReferences(object2, node, processedNodes,
							nodesToDelete);
				}
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public List<CommonIdentified> getMainNodes() {

		List<CommonIdentified> result = new ArrayList<CommonIdentified>();

		List<CommonIdentified> nodesToDelete = new ArrayList<CommonIdentified>();

		try {
			List<String> collections = ReflectionAnalyser
					.getNonNativeCollections(this.getClass());

			for (String fieldName : collections) {
				Collection collection = (Collection) util.getValue(this,
						fieldName);

				result.addAll(collection);

			}

			// return false;

			// for (CommonIdentified toDelete : nodesToDelete) {
			// removeAllReferencesFromNodes(toDelete);
			// }
			return result;

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// RefUtil util = new RefUtil();
		// util.
		return null;
	}

	public boolean isMainNode(CommonIdentified node) {
		// RefUtil util = new RefUtil();
		try {
			List<String> collections = ReflectionAnalyser
					.getNonNativeCollections(this.getClass());

			for (String fieldName : collections) {
				Collection collection = (Collection) util.getValue(this,
						fieldName);
				if (collection.contains(node))
					return true;
			}

			// return false;

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// RefUtil util = new RefUtil();
		// util.
		return false;
	}

	public void compileIndex() {
		// if (index == null)
		index = new IdDatabase();

		// if (modelChangeManager == null)
		modelChangeManager = new ModelChangeManager();

	}

	public void addChild(CommonIdentified node) {
		// recursive mapping of child nodes, list, etc if commonIdentified
		index.storeNode(node);
		modelChangeManager.addedMainNode(node);
	}

	public void removeChild(CommonIdentified node) {
		index.removeNode(node);
		modelChangeManager.removedMainNode(node);

		// remove listeners
		// recursive mapping of child nodes, list, etc if commonIdentified
	}

	public boolean containsStuff() {
		return !index.isEmpty();
	}

	public CommonIdentified getChild(String id) {
		return index.getById(id);
	}

	public IdDatabase getIndex() {
		return index;
	}

	public void setIndex(IdDatabase index) {
		this.index = index;
	}

	public ModelChangeManager getModelChangeManager() {
		return modelChangeManager;
	}

	public void setModelChangeManager(ModelChangeManager modelChangeManager) {
		this.modelChangeManager = modelChangeManager;
	}

}
